package AIColorUSAStates;

import java.util.ArrayList;
import java.util.Random;

import com.google.common.base.Joiner;

public class CustomArrayList<T> extends ArrayList<Node> 
{
	public Node getNode(String name)
	{
		for (Node node : this) 
		{
			if (node.Name.equals(name))
			{
				return node;
			}
		}
		
		return null;
	}
	
	public Node getNodeWithMinCollisions(int plateauTimes)
	{
		// leave Plateau 
		if (Math.random() < (plateauTimes * 0.1))
		{
			Random ran = new Random();
			Node randomNodeWithConflicts = Graph.allNodesInGraph.get(ran.nextInt(Graph.allNodesInGraph.size()));
			while (randomNodeWithConflicts.getCollisions() == 0) 
			{
				randomNodeWithConflicts = Graph.allNodesInGraph.get(ran.nextInt(Graph.allNodesInGraph.size()));
			}
			
			return randomNodeWithConflicts;
		}
		
		// Get Node With minimal Collisions, but not 0
		int minCollisions = Integer.MAX_VALUE;
		for (Node node : this) 
		{
			int nodeCollisions = node.getCollisions();
			if (nodeCollisions < minCollisions && nodeCollisions > 0)
			{
				minCollisions = nodeCollisions;
			}
		}
		
		ArrayList<Node> allNodesWithMinCollisions = new ArrayList<Node>();
		for (Node node : this) 
		{
			if (node.getCollisions() == minCollisions)
			{
				allNodesWithMinCollisions.add(node);
			}
		}
		
		Node maxNei = allNodesWithMinCollisions.get(0);
		for (Node node : allNodesWithMinCollisions) 
		{
			if (node.getNeigSize() > maxNei.getNeigSize())
			{
				maxNei = node;
			}
		}
		
		return maxNei;
		
//		Random ran = new Random();
//		return allNodesWithMinCollisions.get(ran.nextInt(allNodesWithMinCollisions.size()));
	}
	
	public int getMaxCollisions()
	{
		int max = 0;
		for (Node node : this)
		{
			if (max < node.getCollisions())
				max = node.getCollisions();
		}
		
		return max;
	}
	
	public Node getNodeWithMaxConstraints(boolean neiMostHaveAColor)
	{
		// In this case we only want a uncolered node with most neighbours
		if (!neiMostHaveAColor)
		{
			Node nodeMax = null;
			for (Node node : this)
			{
				if (nodeMax == null && node.Color == 0)
					nodeMax = node;
				else if (nodeMax != null && nodeMax.getNeigSize() < node.getNeigSize() && node.Color == 0)
					nodeMax = node;
			}
			
			return nodeMax;
		}
		else 
		{
			// Search all Nodes with Color
			ArrayList<Node> coleredNodes = new ArrayList<Node>();
			
			for (Node node : this) 
			{
				if (node.Color != 0)
				{
					coleredNodes.add(node);
				}
			}
			
			// Search an uncolered neighbour of a colored node with max constrains 
			Node maxNode = null;
			
			// Iterate all colered nodes
			for (int i = 0; i < coleredNodes.size(); i++) 
			{
				// Iterate over all neighbours from colered nodes
				for (int j = 0; j < coleredNodes.get(i).getNeigSize(); j++)
				{
					// We only want uncolored neighbours
					if (maxNode == null 
							&& !coleredNodes.contains(coleredNodes.get(i).getNeighbours().get(j)))
					{
						maxNode = coleredNodes.get(i).getNeighbours().get(j);
					}							
					else if (maxNode != null && maxNode.getNeigSize() < coleredNodes.get(i).getNeighbours().get(j).getNeigSize() 
							&& !coleredNodes.contains(coleredNodes.get(i).getNeighbours().get(j)))
					{
						maxNode = coleredNodes.get(i).getNeighbours().get(j);
					}
				}
			}
			
			return maxNode;
				
		}
		
	}
	
	public int getSumConflicts()
	{
		int sum = 0;
		for (Node node : this) 
		{
			sum += node.getCollisions();
		}
		
		return sum;
	}
	
	@Override
	public String toString()
	{
		StringBuilder builder = new StringBuilder();
				
		for (Node node : this) 
		{
			builder.append("State: ");
			builder.append(node.Name);
			builder.append(" Neighbours ");
			builder.append(Joiner.on(",").join(node.getNeighbours()));
			builder.append(" Collisions: ");
			builder.append(node.getCollisions());
			builder.append(" Color: ");
			builder.append(node.Color);
			builder.append(System.lineSeparator());
		}
		
		return builder.toString();
	}
	
}
